package com.egg.auth.service.login.factory;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.egg.auth.entity.user.User;
import com.egg.auth.entity.user.UserAccount;
import com.egg.auth.enums.account.AccountStateEnum;
import com.egg.auth.enums.account.AccountTypeEnum;
import com.egg.auth.enums.account.DeviceTypeEnum;
import com.egg.auth.enums.user.UserStateEnum;
import com.egg.auth.model.LoginUserInfo;
import com.egg.auth.model.request.Login;
import com.egg.auth.service.login.ILoginFactory;
import com.egg.auth.service.login.LoginHelper;
import com.egg.auth.service.role.IRoleLinkUserService;
import com.egg.auth.service.user.IUserAccountService;
import com.egg.auth.service.user.IUserService;
import com.egg.basic.enums.sms.SmsTypeEnum;
import com.egg.basic.fegin.BasicSmsFeignClient;
import com.egg.common.core.enums.ResponseCode;
import com.egg.common.core.exception.CustomException;
import com.egg.common.core.model.response.ResponseData;
import com.egg.common.util.IdGenUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;
import java.util.Optional;

/**
 * @author east
 */
@Service
public class LoginFactoryPhone implements ILoginFactory, InitializingBean {


    @Autowired
    private BasicSmsFeignClient basicSmsFeignClient;
    @Autowired
    private IUserAccountService userAccountService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IRoleLinkUserService roleLinkUserService;


    @Override
    public void afterPropertiesSet() {
        container.put(AccountTypeEnum.PHONE.getCode(), this);
    }

    @Transactional(rollbackFor = Throwable.class)
    public UserAccount initUserAccount(String username) {
        Optional<User> userOpt = userService.findByPhone(username);
        User user;
        if (userOpt.isPresent()) {
            user = userOpt.get();
        } else {
            user = new User();
            user.setState(UserStateEnum.ENABLED.getCode());
            user.setNickname(IdGenUtil.strId().substring(6));
            userService.baseAdd(user);
        }
        UserAccount userAccount = new UserAccount();
        userAccount.setAccountType(AccountTypeEnum.PHONE.getCode());
        userAccount.setUsername(user.getPhone());
        userAccount.setState(AccountStateEnum.ENABLED.getCode());
        userAccount.setUserId(user.getId());
        userAccountService.baseAdd(userAccount);
        roleLinkUserService.initOnApi(user.getId());
        return userAccount;
    }

    private void verifyCode(String phone, String code) {
        if (ObjectUtil.isEmpty(phone) || ObjectUtil.isEmpty(code)) {
            throw new CustomException("请填写手机与验证码");
        }
        // 这里通过配置获取到注册的模板及签名，通过基础服务发送验证码
        // 除非供应商参数发生极大变化否则当底层短信商发生变动，只需要修改底层即可，这里无需变动。
        ResponseData<Boolean> rd = basicSmsFeignClient.verifySms(phone, SmsTypeEnum.LOGIN, code);
        if (rd.isError()) {
            throw new CustomException("服务器异常,暂时无法注册登录");
        }
        if (!rd.getData()) {
            throw new CustomException("验证码错误");
        }
    }

    @Override
    public ResponseData<String> login(Login login) {
        verifyCode(login.getUsername(), login.getCode());
        Optional<UserAccount> opt = userAccountService.findByUsername(AccountTypeEnum.PHONE.getCode(), login.getUsername());
        UserAccount userAccount = opt.orElseGet(() -> initUserAccount(login.getUsername()));
        if (!Objects.equals(AccountStateEnum.ENABLED.getCode(), userAccount.getState())) {
            return ResponseData.error(ResponseCode.CUSTOM_ERROR.getCode(), "账号非启用状态");
        }
        LoginUserInfo loginUserInfo = LoginHelper.buildLoginUser(AccountTypeEnum.PHONE, opt.get().getUserId());
        LoginHelper.login(loginUserInfo, DeviceTypeEnum.get(login.getDeviceType()));
        return ResponseData.success(StpUtil.getTokenValue());
    }


}
